<?php
/**
 * Created by PhpStorm.
 * User: Qch
 * Date: 2017/9/5
 * Time: 21:19
 */

namespace J\Web;


use J\Message;
use J\ReturnValue;

/**
 * web上下文，处理web输出
 *    可以通过 $context->redirect() 跳转
 *    可以通过 $context->sendException() 发送异常页面
 *
 */
class Context
{
    protected $statusText = '';
    protected $statusCode = 200;

    protected $responseHeaders;

    protected $isSent     = false;
    protected $isRedirect = false;

    /**
     * 跳转部分
     */
    protected $redirectUrl   = null;
    protected $redirectCode  = 302;

    protected $contentTypes;

    /**
     * @var Url
     */
    protected $url;

    /**
     * @var string
     */
    protected $pathinfo;

    /**
     * @return string
     */
    public function getPathinfo()
    {
        return $this->pathinfo;
    }

    /**
     * Context constructor.
     * @param string $pathinfo
     */
    public function __construct($pathinfo = null)
    {
        if($pathinfo === null) {
            $pathinfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
        }
        $this->pathinfo = $pathinfo;
    }


    /**
     * @return Url
     */
    public function getUrl()
    {
        if(!$this->url)  $this->url = new Url();
        return $this->url;
    }

    /**
     * 执行请求并输出（这是整个框架的核心控制部分）
     *
     * @param ReturnValue $r
     * @return bool 后续输出是否有效
     */
    public function response($r)
    {
        $content = $r->getValue();

        // 输出信息自动判定部分

        //    1、输出错误信息并按要求自动跳转（或不跳转）
        if($r->isError()) return $this->sendError($content);
        //    2、没有跳转指示，直接输出
        if (!$this->isRedirect) return $this->sendContent($content);
        //    3、有跳转，但没有提示信息
        if (empty($content)) return $this->directRedirect();
        //    4、输出成功信息并跳转
        return $this->sendSlash(true,$this->redirectUrl, $content);

    }
    /**
     * 根据请求，输出合适的内容
     * @param  string|array $content
     * @return bool 后续输出是否有效
     */
    protected function sendContent($content)
    {
        // 输出格式判定
        if ($this->sendJson($content)) return null;

        // 当你自主输出了内容时，直接返回
        if (is_bool($content) or $content === null) return $content;

        // 输出普通的html页面
        // $content = inject($content);
        echo $content;
        return true;
    }
    /**
     * 发送异常页面
     * @param \Exception $e
     * @return bool
     */
    public function sendException(\Exception $e)
    {
        if($this->sendJson('', false)) return null;

        $this->getUrl()->exceptionView($e);
        return false;
    }
    /**
     * 发送错误页面
     * @param $content
     * @return bool
     */
    protected function sendError($content)
    {
        // 输出格式判定
        if ($this->sendJson($content, false)) return null;
        //
        return $this->sendSlash(false, $this->redirectUrl, $content);

    }
    /**
     * 输出直接跳转页面
     * @return false
     */
    protected function directRedirect()
    {
        $this->setStatusCode($this->redirectCode);
        if (isPjax()) {
            $this->responseHeaders['X-Pjax-Url'] = $this->redirectUrl;
        } elseif (isAjax()) {
            $this->responseHeaders['X-Redirect'] = $this->redirectUrl;
        } else {
            $this->responseHeaders['Location'] = $this->redirectUrl;
        }
        $this->sendHeaders();
        // 直接跳转页面不再输出其它内容
        return false;
    }
    /**
     * 输出提示页面
     * @param bool   $isSuccess
     * @param string $jumpUrl
     * @param string $message
     * @param int    $waitSecond
     * @return bool
     */
    public function sendSlash($isSuccess,$jumpUrl, $message, $waitSecond = 5)
    {
        $this->getUrl()->slashView(compact('isSuccess','jumpUrl', 'message','waitSecond'));
        // 提示跳转页面后续是否有效不确定
        return $isSuccess;
    }
    /**
     * 跳转命令, （在response方法中）自动跳转
     *
     * @param string $url 地址
     * @param int $statusCode 状态码
     * @return $this
     */
    public function redirect($url, $statusCode = 302)
    {
        $this->isRedirect = true;

        $this->redirectUrl = $url;
        $this->redirectCode = $statusCode;

        return $this;
    }

    protected function sendJson($content,  $status = true)
    {
        if (is_array($content) or isJsonSend()) {
            if (!is_array($content)) $content = value_ajax($status, $content);
            if (!isset($content['status'])) $content['status'] = $status;
            echo json_print($content);
            return true;
        }
        return false;
    }

    public function setStatusCode($value, $text = null)
    {
        if ($value === null) {
            $value = 200;
        }
        $this->statusCode = (int)$value;
        if (isInvalidStatusCode($this->statusCode)) {
            app()->error(Message::INVALID_STATUS_CODE, ['statusCode' => $this->statusCode]);
            return;
        }
        if ($text === null) {
            $this->statusText = isset(HttpStatus::$httpStatuses[$this->statusCode]) ? HttpStatus::$httpStatuses[$this->statusCode] : '';
        } else {
            $this->statusText = $text;
        }
    }

    protected function sendHeaders()
    {
        if (headers_sent()) {
            return;
        }
        $statusCode = $this->statusCode;
        $version = http_version();
        header("HTTP/{$version} $statusCode {$this->statusText}");
        if ($this->responseHeaders) {
            $headers = $this->getResponseHeaders();
            foreach ($headers as $name => $values) {
                $name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
                // set replace for first occurrence of header but false afterwards to allow multiple
                if(!is_array($values)){
                    header("$name: $values");
                    continue;
                }
                $replace = true;
                foreach ($values as $value) {
                    header("$name: $value", $replace);
                    $replace = false;
                }
            }
        }

    }

    /**
     * HTTP Header
     * @return array the header collection
     */
    public function getResponseHeaders()
    {
        return $this->responseHeaders;
    }
}